[Amazon SageMaker] 組み込みアルゴリズムのオブジェクト検出(ResNet-50)をRaspberryPi上のMXNetで利用してみました
1 はじめに
CX事業本部の平内(SIN)です。
先日、Amazon SageMaker(以下、SageMaker)のビルトインアルゴリズムであるオブジェクト検出(Object Detection)で作成したモデルを変換して、MacOSにインストールしたMXNet上で利用してみました。
今回は、同じ要領で、RaspberryPiで利用可能かどうかを確認してみました。
結論(感想)から言ってしまうと・・・動作はしますが、推論にちょっと時間がかかるため、リアルタイム的な利用は難しいという感じです。
2 RaspberryPi
Raspberri Piは、Model4で、OSは、今年5月の最新版(Raspberry Pi OS (32-bit) with desktop and recommended software)2020-05-27-raspios-buster-full-armhf.img です
$ cat /proc/cpuinfo | grep Revision Revision : c03112 $ lsb_release -a No LSB modules are available. Distributor ID: Raspbian Description: Raspbian GNU/Linux 10 (buster) Release: 10 Codename: buster $ uname -a Linux raspberrypi 4.19.118-v7l+ #1311 SMP Mon Apr 27 14:26:42 BST 2020 armv7l GNU/Linux
3 MXNet
MXNetは、最新の1.6.0が、ちょっとうまく動作させることが出来ず、1つ前の1.5.0を利用しました。
(1) Ver 1.6.0
下記のように、pipを利用すると、最新の1.6.0がインストールされます。
$ pip3 install mxnet
しかし、importの段階で、下記のようなエラーとなってしまいました。
$ python3 >>> import mxnet OSError: /home/pi/.local/lib/python3.7/site-packages/mxnet/libmxnet.so: wrong ELF class: ELFCLASS64 >>>
今回は、上記エラーの回避を諦めました。
(2) Ver 1.5.0
1.5.0のインストールは、下記に置かれている、mxnet-1.6.0-py2.py3-none-any.whlを利用させて頂きました。
http://mxnet-public.s3.amazonaws.com/
pipでのインストールは、以下のとおりです。
$ pip3 install https://mxnet-public.s3.amazonaws.com/install/raspbian/mxnet-1.5.0-py2.py3-none-any.whl Successfully built numpy Installing collected packages: numpy, mxnet Successfully installed mxnet-1.5.0 numpy-1.15.2
なお、上記のインストールだけでは、ライブラリ不足となっておりましたので、これを追加しました。
OSError: libopenblas.so.0: cannot open shared object file: No such file or directory
$ sudo apt-get install libopenblas-base
バージョン1.5.0が、利用可能になっている様子です。
$ python3 Python 3.7.3 (default, Dec 20 2019, 18:57:59) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import numpy >>> import mxnet >>> mxnet.__version__ '1.5.0' >>>
参考:https://github.com/apache/incubator-mxnet/issues/17978
4 利用状況
RaspberryPi上で推論している様子です。時間はかかりますが、一応、動作できています。
下記が、ログの一例です。1回の推論に10秒弱かかっています。
$ python3 index.py [04:57:56] /work/mxnet/src/nnvm/legacy_json_util.cc:204: Warning: loading symbol saved by MXNet version 10501 with lower version of MXNet v10500. May cause undefined behavior. Please update MXNet if you encounter any issue fps:24.0 width:800.0 height:600.0 inference start [PRETZEL]0.8488292694091797 21, 45, 353, 487 inference finish:9.958193302154541[sec] inference start [PRIME]0.836922824382782 98, 118, 388, 499 inference finish:9.596295356750488[sec] inference start [OREO]0.9958897233009338 57, 155, 449, 502 inference finish:9.709836483001709[sec] inference start [CRATZ]0.9407762289047241 21, 88, 322, 468 inference finish:9.705724239349365[sec] inference start [ASPARA]0.7363123297691345 57, 134, 368, 511 inference finish:9.655270338058472[sec]
5 コード
使用したPython3のコードは、以下のとおりです。
変換で生成したモデルを、./modelに置き、Webカメラの画像を入力インターフェースに変換して推論にかけています。
import mxnet as mx import cv2 import time import numpy as np from collections import namedtuple # Webカメラ DEVICE_ID = 0 WIDTH = 800 HEIGHT = 600 FPS = 24 MODEL_PATH = './model/deploy_model_algo_1' CLASSES = ['ASPARA','CRATZ','PRETZEL','PRIME','OREO'] COLORS = [(128, 0, 0),(0, 128, 0),(0, 0, 128),(128, 128, 0),(0, 128,128)] def main(): # Model Initialize SHAPE = 512 input_shapes=[('data', (1, 3, SHAPE, SHAPE))] Batch = namedtuple('Batch', ['data']) sym, arg_params, aux_params = mx.model.load_checkpoint(MODEL_PATH, 0) mod = mx.mod.Module(symbol=sym, label_names=[], context=mx.cpu()) mod.bind(for_training=False, data_shapes=input_shapes) mod.set_params(arg_params, aux_params) # Video Initialize cap = cv2.VideoCapture (DEVICE_ID) cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT) cap.set(cv2.CAP_PROP_FPS, FPS) width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) fps = cap.get(cv2.CAP_PROP_FPS) print("fps:{} width:{} height:{}".format(fps, width, height)) while True: # カメラ画像取得 _, frame = cap.read() if(frame is None): continue print("inference start") start = time.time() # 入力インターフェースへの画像変換 frame = frame[0 : int(height), 0 : int(height)] # 800*600 -> 600*600 frame = cv2.resize(frame, (SHAPE, SHAPE)) # 600*600 -> 512*512 img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # BGR -> RGB img = img.transpose((2, 0, 1)) # 512,512,3 -> 3,512,512 img = img[np.newaxis, :] # 3,512,512 -> 1,3,512,512 # 推論 mod.forward(Batch([mx.nd.array(img)])) prob = mod.get_outputs()[0].asnumpy() prob = np.squeeze(prob) index = int(prob[:, 0][0]) confidence = prob[0][1] x1 = int(prob[0][2] * SHAPE) y1 = int(prob[0][3] * SHAPE) x2 = int(prob[0][4] * SHAPE) y2 = int(prob[0][5] * SHAPE) # 表示 print("[{}]{} {}, {}, {}, {}".format(CLASSES[index], confidence, x1, y1, x2, y2)) if(confidence > 0.6): # 信頼度 frame = cv2.rectangle(frame,(x1, y1), (x2, y2), COLORS[index],2) frame = cv2.rectangle(frame,(x1, y1), (x1 + 150,y1-20), COLORS[index], -1) label = "{} {:.2f}".format(CLASSES[index], confidence) frame = cv2.putText(frame,label,(x1+2, y1-2), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 1, cv2.LINE_AA) elapsed_time = time.time() - start print ("inference finish:{0}".format(elapsed_time) + "[sec]") # 画像表示 cv2.imshow('frame', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break # 読み飛ばし for _ in range(int(fps*10)): _, dmy = cap.read() cap.release() cv2.destroyAllWindows() if __name__ == '__main__': main()
6 最後に
今回は、RaspberryPiにインストールしたMXNet上で試してみました。
推論に10秒程度必要ということで、リアルタイム(的)な要件には、ちょっと厳しいと思います。しかし、推論にかかるコストは非常に低くなると思うので、要件によっては有りかも知れません。